using System;
using System.Text;
using HttpServer;
using HttpServer.BodyDecoders;
using HttpServer.Headers;
using HttpServer.Logging;
using HttpServer.Routing;
using ZMQ;
using System.Threading;
using System.ComponentModel;
using System.Collections.Generic;

namespace CrawlRemix
{
	/// <summary>
	/// 
	/// </summary>
    public sealed class MainClass
	{
        /// <summary>
        /// 
        /// </summary>
        private Socket skt;

        /// <summary>
        /// 
        /// </summary>
        private Context ctx;

        /// <summary>
        /// 
        /// </summary>
        private bool ok = false;

        /// <summary>
        /// worker for bot
        /// </summary>
        private BackgroundWorker worker;

        /// <summary>
        /// the bot
        /// </summary>
        private TachBot tb;

        /// <summary>
        /// Messages
        /// </summary>
        private List<string> messages;

        /// <summary>
        /// ajax update number
        /// </summary>
        private int updateLog = 0;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainClass"/> class.
        /// </summary>
        public MainClass()
		{
		}

        /// <summary>
        /// Mains the specified args.
        /// </summary>
        /// <param name="args">The args.</param>
		public static void Main (string[] args)
		{
		    MainClass m = new MainClass();
			m.Run();
		}

        /// <summary>
        /// Runs this instance.
        /// </summary>
		private void Run()
		{
			LogFilter filter = new LogFilter();
            filter.AddType(typeof(HttpServer.Messages.MessageFactoryContext), LogLevel.Error);
            filter.AddType(typeof(HttpServer.Messages.ResponseWriter), LogLevel.Error);
            filter.AddType(typeof(HttpServer.Messages.Parser.HttpParser), LogLevel.Error);
			filter.AddType(typeof(TachModule), LogLevel.Error);
            filter.AddType(typeof(HttpContext), LogLevel.Error);
            filter.AddType(typeof(HttpFactory), LogLevel.Error);
            filter.AddType(typeof(HttpListener), LogLevel.Error);
            filter.AddType(typeof(SimpleRouter), LogLevel.Error);
            filter.AddType(typeof(Server), LogLevel.Error);
			LogFactory.Assign(new TachLogFactory(filter));
			
            // Initialise 0MQ infrastructure
            string address = "inproc://tachbot";
            ctx = new Context(1);
            skt = ctx.Socket(SocketType.REP);
            skt.Bind(address);
            ThreadStart thrts = new ThreadStart(ZmqLoop);
            Thread zmqThr = new Thread(thrts);
            zmqThr.IsBackground = true;
            ok = true;
            zmqThr.Start();

            // Create server
            Server server = new Server();

            TachModule tm = new TachModule(this.ctx);
            server.Add(tm);

            // nom requests
            server.RequestReceived += OnRequest;
            
            // add decoder
            server.Add(new MultiPartDecoder());

            // Add listener
            server.Add(HttpListener.Create(System.Net.IPAddress.Any, 8089));

            // Add Router
            server.Add(new SimpleRouter("/", "/index.html"));

            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            tb = new TachBot();
            messages = new List<string>();
            CrawlRemix.TachBot.Add += new AddText(tb_Add);

            // Start server
            server.Start(5);

            Timer tim = new Timer(new TimerCallback(this.Loggin), null, 5000, 16000);
            
            // Wait
            Console.WriteLine("Hey.");
            Console.ReadKey();
            ok = false;
            tm.Close();
		}

        /// <summary>
        /// Loggins the specified arg.
        /// </summary>
        /// <param name="arg">The arg.</param>
        private void Loggin(object arg)
        {
            TachBot.AddText("bouncy");
        }

        /// <summary>
        /// Handles the RunWorkerCompleted event of the worker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                this.tb_Add(e.Error.ToString());
            }
        }

        /// <summary>
        /// Add string
        /// </summary>
        /// <param name="message">MEssage</param>
        private void tb_Add(string message)
        {
            this.messages.Add(message);
            if (this.messages.Count > 50)
            {
                this.messages.RemoveAt(0);
            }

            this.updateLog++;
        }

        /// <summary>
        /// DoWork
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Args</param>
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            string msg = e.Argument as string;
            if ((msg == "pages") || (msg == "categories") || (msg == "templates"))
            {
                tb.GetDoWork(msg);
            }
            else if (msg == "resetpages")
            {
                tb.ResetPages();
            }
            else if (msg == "parsepages")
            {
                tb.ParsePages();
            }
        }

        /// <summary>
        /// ZMQ main loop.
        /// </summary>
        private void ZmqLoop()
        {
            while (ok)
            {
                // Wait for the first message.
                string msg = string.Empty;
                msg = skt.Recv(Encoding.Unicode, new SendRecvOpt[] { SendRecvOpt.NONE });
                if (msg.Contains(":"))
                {
                    string[] split = msg.Split(new char[] { ':' });
                    int num = 0;
                    try
                    {
                        num = int.Parse(split[1]);
                    }
                    catch (FormatException)
                    {
                    }
                    
                    if (split[0] == "getmessages")
                    {
                        string ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<response>\n";
                        ret += "<update>" + this.updateLog.ToString() + "</update>\n" + "<data><span>";
                        if (updateLog != num)
                        {
                            foreach (string message in messages)
                            {
                                ret += message + "<br />\n";
                            }
                        }

                        ret += "</span></data>\n</response>\n";
                        skt.Send(ret, Encoding.Unicode);
                    }
                    else if (split[0] == "getpagelist")
                    {
                        string ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<response>\n";
                        ret += "<update>" + this.updateLog.ToString() + "</update>\n" + "<data><div>";
                        if (updateLog != num)
                        {
                            ret += "<table>\n";
                            IList<Tachbot.Tbwiki> pages = tb.Pages();
                            if (pages.Count > 0)
                            {
                                foreach (Tachbot.Tbwiki tbw in pages)
                                {
                                    ret += "<tr><td>" + tbw.Id + "</td><td>" + tbw.Page + "</td><td>" + tbw.Enabled + "</td><td>" +
                                        tbw.Count + "</td></tr>\n";
                                }
                            }
                            else
                            {
                                ret += "<tr><td>0</td><td>na</td><td>na</td><td>0</td></tr>\n";
                            }
                            
                            ret += "</table>\n";
                        }
                        
                        ret += "</div></data>\n</response>\n";
                        skt.Send(ret, Encoding.Unicode);
                    }
                }
                else
                {
                    if ((msg == "pages") || (msg == "categories") || (msg == "templates"))
                    {
                        if (worker.IsBusy)
                        {
                            skt.Send("busy", Encoding.Unicode);
                        }
                        else
                        {
                            worker.RunWorkerAsync(msg);
                            skt.Send(msg + " start", Encoding.Unicode);
                        }
                    }
                    else if (msg == "resetpages")
                    {
                        if (worker.IsBusy)
                        {
                            skt.Send("busy", Encoding.Unicode);
                        }
                        else
                        {
                            worker.RunWorkerAsync(msg);
                            skt.Send(msg + " start", Encoding.Unicode);
                        }
                    }
                    else if (msg == "parsepages")
                    {
                        if (worker.IsBusy)
                        {
                            skt.Send("busy", Encoding.Unicode);
                        }
                        else
                        {
                            worker.RunWorkerAsync(msg);
                            skt.Send(msg + " start", Encoding.Unicode);
                        }
                    }
                    else if (msg == "getstate")
                    {
                        if (worker.IsBusy)
                        {
                            skt.Send("busy", Encoding.Unicode);
                        }
                        else
                        {
                            skt.Send("idle", Encoding.Unicode);
                        }
                    }
                    else
                    {
                        skt.Send(msg + "??", Encoding.Unicode);
                    }
                }
            }

            skt.Dispose();
            ctx.Dispose();
        }

        /// <summary>
        /// Called on request.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="HttpServer.RequestEventArgs"/> instance containing the event data.</param>
		private void OnRequest(object sender, RequestEventArgs e)
		{
		}
	}
}
